package com.zaicheng.cloud.netty.server;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zaicheng.cloud.App;
import com.zaicheng.cloud.netty.RpcRequest;
import com.zaicheng.cloud.netty.protocol.*;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.Random;

/**
 @author zaicheng
 @version 1.0
 @date 2022-04-19
 @email zzc15847256473@163.com
 */
@Slf4j
@Service
public class NettyServer implements Runnable{

    private ApplicationContext applicationContext;

    public NettyServer(ApplicationContext context) {
         this.applicationContext = context;
         new Thread(this).start();
    }

    // 启动服务端端
    public  void startServer0(int port){

        EventLoopGroup bossGroup = new NioEventLoopGroup(3);
        EventLoopGroup workGroup = new NioEventLoopGroup(8);
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,workGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,1024)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new ProtoStuffDecoder(MessageContext.class));
                            pipeline.addLast(new ProtoStuffEncoder());
                            pipeline.addLast(new NettyServerHandler(applicationContext));
//                            pipeline.addLast(new SimpleChannelInboundHandler<MessageContext>() {
//                                @Override
//                                protected void channelRead0(ChannelHandlerContext channelHandlerContext, MessageContext request) throws Exception {
//                                    // 解析参数
//                                    Object requestData = request.getData();
//                                    Request requestJson = JSON.parseObject(JSONObject.toJSONString(requestData), Request.class);
//                                    Class<?>[] paramTypes = requestJson.getParameterTypes();
//                                    Class<?> clazz = requestJson.getClazz();
//                                    String methodName = requestJson.getMethodName();
//                                    Object[] args = requestJson.getArgs();
//
//                                    Class<?> returnType = null;
//                                    Object invoke = null;
//                                    if (Objects.nonNull(paramTypes) && Objects.isNull(args)){
//                                        // 反射调用
//                                        Method method = clazz.getMethod(methodName);
//                                        returnType = method.getReturnType();
//                                        invoke = method.invoke(applicationContext.getBean(clazz), args);
//                                    }else {
//                                        if (paramTypes.length == args.length) {
//                                            for (int i = 0; i < args.length; i++) {
//                                                Object object = JSON.parseObject(JSONObject.toJSONString(args[i]), paramTypes[i]);
//                                                args[i] = object;
//                                            }
//                                        }
//                                        // 反射调用
//                                        Method method = clazz.getMethod(methodName, paramTypes);
//                                        returnType = method.getReturnType();
//                                        invoke = method.invoke(applicationContext.getBean(clazz), args);
//                                    }
//                                    // 封装结果
//                                    MessageContext messageContext = new MessageContext(String.valueOf(new Random().nextInt(9999)),true,new Response(true,invoke,returnType));
//                                    log.info("RPC 请求调用 clazz:{} methodName:{}, response:{}", clazz.getName(), methodName, JSON.toJSON(messageContext));
//                                    // 回写数据
//                                    channelHandlerContext.channel().writeAndFlush(messageContext);
//                                }
//                            });
                        }
                    });
            ChannelFuture channelFuture = serverBootstrap.bind(port).await();
            System.out.println("Netty server start...");
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
           startServer0(7002);
    }
}
